home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / satellit / pfh0210 / pfh.c < prev    next >
C/C++ Source or Header  |  1991-02-03  |  24KB  |  1,107 lines

  1. /* several utility functions involving the Pacsat File Header */
  2. /* copyright 1991 by PE1CHL */
  3.  
  4. #include <stdio.h>
  5. #include <time.h>
  6. #if defined(__TURBOC__) || defined(MSDOS)
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #else
  10. extern char *strstr();
  11. #endif
  12.  
  13. /* definition of a PFH item (used for verbose printout of PFH and user input) */
  14. struct pfh
  15. {
  16.     unsigned int id;            /* PFH ID */
  17.     unsigned char type;            /* printout type */
  18. #define TEXT    0
  19. #define BYTE    1
  20. #define WORD    2
  21. #define TIME    3
  22. #define LONG    4
  23. #define DUMP    5
  24. #define SEU    6
  25. #define COMP    7
  26.     unsigned char flags;        /* various attributes: */
  27. #define SUPPR    0x01            /* suppress it when -s? */
  28. #define MAND    0x02            /* mandatory item */
  29. #define PROMPT    0x04            /* prompt for user input */
  30. #define SPACE    0x08            /* init to spaces */
  31.     unsigned char len;            /* default/max length for pfhadd */
  32.     char *title;
  33. };
  34.  
  35. /* table of known pfh items and their types and names */
  36. struct pfh pfh[] =
  37. {
  38.     0x01, LONG, 0x02, 4, "File-number",
  39.     0x02, TEXT, 0x0b, 8, "File-name",
  40.     0x03, TEXT, 0x0b, 3, "File-ext",
  41.     0x04, LONG, 0x02, 4, "File-size",
  42.     0x05, TIME, 0x02, 4, "Create-time",
  43.     0x06, TIME, 0x03, 4, "Last-modified-time",
  44.     0x07, SEU,    0x02, 1, "SEU-flag",
  45.     0x08, BYTE, 0x06, 1, "File-type",
  46.     0x09, WORD, 0x03, 2, "Body-checksum",
  47.     0x0a, WORD, 0x03, 2, "Header-checksum",
  48.     0x0b, WORD, 0x03, 2, "Body-offset",
  49.  
  50.     0x10, TEXT, 0x06, 0, "Source",
  51.     0x11, TEXT, 0x0a, 6, "AX25-Uploader",
  52.     0x12, TIME, 0x02, 4, "Upload-time",
  53.     0x13, BYTE, 0x02, 1, "Download-count",
  54.     0x14, TEXT, 0x06, 0, "Destination",
  55.     0x15, TEXT, 0x0b, 6, "AX25-Downloader",
  56.     0x16, TIME, 0x02, 4, "Download-time",
  57.     0x17, TIME, 0x02, 4, "Expire-time",
  58.     0x18, BYTE, 0x07, 1, "Priority",
  59.  
  60.     0x19, COMP, 0x04, 1, "Compression-type",
  61.     0x20, TEXT, 0x04, 1, "BBS-Message-type",
  62.     0x21, TEXT, 0x04, 0, "Bulletin-ID",
  63.     0x22, TEXT, 0x04, 0, "Title",
  64.     0x23, TEXT, 0x04, 0, "Keywords",
  65.     0x24, TEXT, 0x00, 0, "File-Description",
  66.     0x25, TEXT, 0x00, 0, "Compression-Description",
  67.     0x26, TEXT, 0x00, 0, "User-Filename",
  68.     0,      DUMP, 0x00, 0, "Unknown-Header-type"
  69. };
  70.  
  71.  
  72. char nopfh[] = "%s: no Pacsat File Header\n";
  73. char headcsum[] = "Warning: %s: header checksum error (%04x)\n";
  74. char bodycsum[] = "Warning: %s: body checksum error (%04x)\n";
  75. char writeerr[] = "Warning: write error in %s (disk full?)\n";
  76. char linehead[] = " File_ID Ty Length To          From      Date/Time Title\n";
  77. char hightext[] = "Hightime: %lx = %02d%02d%02d%02d%02d%02d (%.24s)\n";
  78.  
  79. char nomem[] = "Out of memory!\n";
  80.  
  81. unsigned char data[2048];            /* buffer */
  82. char source[256];
  83. char dest[256];
  84. char title[256];
  85.  
  86. time_t hightime = 0;                /* ul_time of newest file */
  87.  
  88.  
  89. #if defined(__TURBOC__) || defined(MSDOS)
  90. int pfhprint(char *,char *,int,int,int);
  91. int pfhdir(char *);
  92. int pfhtoc(int,char **);
  93. int pfhline(char *,FILE *);
  94. int cleandir(char *);
  95. int pfhadd(char *,char *);
  96. #else
  97. int pfhprint(),pfhdir(),pfhtoc(),pfhline(),cleandir(),pfhadd();
  98. #endif
  99.  
  100. /* main program. parse options, check argcount and call proper function */
  101. int main (argc,argv)
  102.     int argc;
  103.     char *argv[];
  104.  
  105. {
  106.     int opermode = 0;            /* operation mode (pfh/dir/toc) */
  107.     int suppress = 0;            /* suppress some pfh items */
  108.     int headonly = 0;            /* show only header, not file */
  109.     int strip7 = 0;            /* bit-7 strip on body */
  110.     char *p;
  111.  
  112.     /* get options */
  113.  
  114.     while (argc > 1 && (argv[1][0] == '-' || argv[1][0] == '/'))
  115.     {
  116.     for (p = argv[1] + 1; *p; p++)
  117.         switch (*p)
  118.         {
  119.         case 'd':
  120.         case 'D':
  121.         opermode = 1;        /* dirfile printout (short form) */
  122.         break;
  123.  
  124.         case 't':
  125.         case 'T':
  126.         opermode = 2;        /* toc of series of files (short form) */
  127.         break;
  128.  
  129.         case 'c':
  130.         case 'C':
  131.         opermode = 3;        /* cleanup a dirfile.dl file */
  132.         break;
  133.  
  134.         case 'a':
  135.         case 'A':
  136.         opermode = 4;        /* add PFH to file */
  137.         break;
  138.  
  139.         case 's':
  140.         case 'S':
  141.         suppress = 1;        /* omit boring headers */
  142.         break;
  143.  
  144.         case 'h':
  145.         case 'H':
  146.         headonly = 1;        /* don't output body */
  147.         break;
  148.  
  149.         case '7':
  150.         strip7 = 1;        /* strip bit 7 off Jeff's WS files */
  151.         break;
  152.  
  153.         default:
  154.         argc = 0;        /* force usage message */
  155.         break;
  156.         }
  157.  
  158.     argv++;
  159.     argc--;
  160.     }
  161.  
  162.     switch (opermode)
  163.     {
  164.     case 0:
  165.     if (argc == 2 || argc == 3)
  166.         return pfhprint(argv[1],argv[2],suppress,headonly,strip7);
  167.  
  168.     break;
  169.  
  170.     case 1:
  171.     if (argc == 2)
  172.         return pfhdir(argv[1]);
  173.  
  174.     break;
  175.  
  176.     case 2:
  177.     if (argc >= 2)
  178.         return pfhtoc(argc,argv);
  179.  
  180.     break;
  181.  
  182.     case 3:
  183.     if (argc == 2)
  184.         return cleandir(argv[1]);
  185.  
  186.     break;
  187.  
  188.     case 4:
  189.     if (argc == 3)
  190.         return pfhadd(argv[1],argv[2]);
  191.  
  192.     break;
  193.     }
  194.  
  195.     /* print usage message in case of arg error */
  196.  
  197.     fprintf(stderr,"Usage: pfh [-s] [-h] [-7] <inputfile> [<outputfile>]\n");
  198.     fprintf(stderr,"       interprets Pacsat File Header on file\n");
  199.     fprintf(stderr,"       when <outputfile> specified, body is copied to it\n");
  200.     fprintf(stderr,"       -s option suppresses certain header items\n");
  201.     fprintf(stderr,"       -h option prints only the header, not the body\n");
  202.     fprintf(stderr,"       -7 option strips high bit when copying the body\n\n");
  203.     fprintf(stderr,"or:    pfh -t <inputfile>...\n");
  204.     fprintf(stderr,"       prints PFH items in <inputfile>s in short format\n\n");
  205.     fprintf(stderr,"or:    pfh -d <dirfile>\n");
  206.     fprintf(stderr,"       prints PFH items in <dirfile> in short format\n\n");
  207.     fprintf(stderr,"or:    pfh -c <dirfile>\n");
  208.     fprintf(stderr,"       cleans <dirfile> (removes duplicate entries & sorts)\n\n");
  209.     fprintf(stderr,"or:    pfh -a <inputfile> <outputfile>\n");
  210.     fprintf(stderr,"       adds PFH to file (prompts for header values)\n\n");
  211.     fprintf(stderr,"PFH utility program (c) 1991 by Rob Janssen, PE1CHL\n");
  212.  
  213.     return 1;
  214. }
  215.  
  216. /* printout PFH for specified inputfile, and copy body to specified    */
  217. /* outputfile, to stdout, or omit entirely                */
  218.  
  219. pfhprint (inputfile,outputfile,suppress,headonly,strip7)
  220.     char *inputfile;            /* inputfile name */
  221.     char *outputfile;            /* outputfile, or NULL for stdout */
  222.     int suppress;            /* header suppress flag */
  223.     int headonly;            /* body omission flag */
  224.     int strip7;                /* strip-high-bit flag */
  225.  
  226. {
  227.     FILE *inp,*out;
  228.     int id,id2,len,i;
  229.     unsigned long val;
  230.     unsigned int hsum,bsum,csum;
  231.  
  232.     /* open inputfile */
  233.  
  234.     if ((inp = fopen(inputfile,"rb")) == NULL)
  235.     {
  236.     perror(inputfile);
  237.     return 2;
  238.     }
  239.  
  240.     /* check magic number AA55 */
  241.  
  242.     if (fgetc(inp) != 0xaa || fgetc(inp) != 0x55)
  243.     {
  244.     fprintf(stderr,nopfh,inputfile);
  245.     fclose(inp);
  246.     return 3;
  247.     }
  248.  
  249.     csum = 0xaa + 0x55;
  250.  
  251.     /* read header items */
  252.  
  253.     while ((id = fgetc(inp)) != EOF &&
  254.        (id2 = fgetc(inp)) != EOF &&
  255.        (len = fgetc(inp)) != EOF)
  256.     {
  257.     csum += id + id2 + len;            /* update header checksum */
  258.  
  259.     id |= id2 << 8;
  260.  
  261.     if (id == 0 && len == 0)        /* end of header? */
  262.         break;
  263.  
  264.     if (fread(data,1,len,inp) != len)    /* read data */
  265.         break;
  266.  
  267.     data[len] = '\0';
  268.  
  269.     if (len <= 4)
  270.     {
  271.         val = 0;
  272.  
  273.         for (i = 0; i < len; i++)
  274.         val |= (unsigned long) data[i] << (8 * i);
  275.     }
  276.  
  277.     /* special treatment for some header items */
  278.     switch (id)
  279.     {
  280.     case 0x0a:                /* header checksum */
  281.         hsum = (unsigned)val;        /* get it's value */
  282.         break;                /* and don't update csum */
  283.  
  284.     case 0x09:                /* body checksum */
  285.         bsum = (unsigned)val;        /* get value & update csum */
  286.  
  287.     default:
  288.         for (i = 0; i < len; i++)
  289.         csum += data[i];        /* update header checksum */
  290.         break;
  291.     }
  292.  
  293.     for (i = 0; pfh[i].id != 0; i++)
  294.         if (pfh[i].id == id)
  295.         break;
  296.  
  297.     if (suppress && (pfh[i].flags & SUPPR))
  298.         continue;
  299.  
  300.     printf("%s: ",pfh[i].title);
  301.  
  302.     switch (pfh[i].type)
  303.     {
  304.     case TEXT:
  305.         if (data[0] == ' ' || data[strlen((char *) data) - 1] == ' ')
  306.         printf("\"%s\"\n",data);
  307.         else
  308.         printf("%s\n",data);
  309.         break;
  310.  
  311.     case TIME:
  312.         if (len != 4)
  313.         goto badlen;
  314.  
  315.         if (val == 0)
  316.         printf("not initialized\n");
  317.         else
  318.         printf("%.24s\n",ctime((time_t *) &val));
  319.         break;
  320.  
  321.     case SEU:
  322.         if (len != 1)
  323.         goto badlen;
  324.  
  325.         switch (data[0])
  326.         {
  327.         case 0:
  328.         printf("no Single Event Upsets\n");
  329.         break;
  330.  
  331.         case 2:
  332.         printf("un");
  333.         case 1:
  334.         printf("correctable Single Event Upsets occurred\n");
  335.         break;
  336.  
  337.         default:
  338.         printf("%u\n",data[0]);
  339.         }
  340.         break;
  341.  
  342.     case COMP:
  343.         if (len != 1)
  344.         goto badlen;
  345.  
  346.         switch (data[0])
  347.         {
  348.         case 0:
  349.         printf("not compressed\n");
  350.         break;
  351.  
  352.         case 1:
  353.         printf("compressed using PKARC\n");
  354.         break;
  355.  
  356.         case 2:
  357.         printf("compressed using PKZIP\n");
  358.         break;
  359.  
  360.         case 255:
  361.         printf("see Compression-Description\n");
  362.         break;
  363.  
  364.         default:
  365.         printf("0x%02x\n",data[0]);
  366.         break;
  367.         }
  368.         break;
  369.  
  370.     case BYTE:
  371.     case WORD:
  372.     case LONG:
  373.         if (len == pfh[i].type)
  374.         {
  375.         printf("0x%0*lx %lu\n",len * 2,val,val);
  376.         break;
  377.         }
  378.  
  379.     badlen:
  380.     default:
  381.         printf("id=0x%02x len=%d val=0x",id,len);
  382.         for (i = 0; i < len; i++)
  383.         printf("%02x",data[i]);
  384.         printf("\n");
  385.         break;
  386.     }
  387.     }
  388.  
  389.     fflush(stdout);
  390.  
  391.     if (hsum != csum)
  392.     fprintf(stderr,headcsum,inputfile,csum);
  393.  
  394.     csum = 0;
  395.  
  396.     /* test for outputfile requirement */
  397.  
  398.     if (!headonly && outputfile != NULL)
  399.     {
  400.     /* create outputfile */
  401.  
  402.     if ((out = fopen(outputfile,"wb")) == NULL)
  403.     {
  404.         perror(outputfile);
  405.         fclose(inp);
  406.         return 4;
  407.     }
  408.  
  409.     /* copy rest of inputfile to ouputfile */
  410.  
  411.     while ((len = (int)fread(data,1,sizeof(data),inp)) != 0) /* read data */
  412.     {
  413.         for (i = 0; i < len; i++)
  414.         {
  415.         csum += data[i];        /* calc checksum */
  416.  
  417.         if (strip7)
  418.             data[i] &= 0x7f;        /* clear high bit */
  419.         }
  420.  
  421.         if (fwrite(data,1,len,out) != len)    /* write to output */
  422.         {
  423.         perror(outputfile);
  424.         break;
  425.         }
  426.     }
  427.  
  428.     if (ferror(out) || fclose(out) == EOF)
  429.         fprintf(stderr,writeerr,outputfile);
  430.     }
  431.     else
  432.     {
  433.     /* body to stdout, blank line between headers and body */
  434.  
  435.     if (!headonly)
  436.         printf("\n");
  437.  
  438.     /* read body and translate \r\n to \n on output */
  439.  
  440.     while ((i = fgetc(inp)) != EOF)
  441.     {
  442.         csum += i;
  443.  
  444.         if (headonly)
  445.         continue;
  446.  
  447.         if (strip7)
  448.         i &= 0x7f;
  449.  
  450.         if (i == '\r')
  451.         {
  452.         i = fgetc(inp);
  453.         csum += i;
  454.  
  455.         if (strip7)
  456.             i &= 0x7f;
  457.  
  458.         if (i == '\n')
  459.             printf("\n");
  460.         else
  461.             printf("\r%c",i);
  462.         }
  463.         else
  464.         printf("%c",i);
  465.     }
  466.     }
  467.  
  468.     fflush(stdout);
  469.  
  470.     if (bsum != csum)
  471.     fprintf(stderr,bodycsum,inputfile,csum);
  472.  
  473.     fclose(inp);
  474.     return 0;
  475. }
  476.  
  477. /* printout a downloaded directory (SELECT + DIR commands) */
  478. pfhdir (inputfile)
  479.     char *inputfile;
  480.  
  481. {
  482.     FILE *inp;
  483.     struct tm *tm;
  484.  
  485.     /* open inputfile */
  486.  
  487.     if ((inp = fopen(inputfile,"rb")) == NULL)
  488.     {
  489.     perror(inputfile);
  490.     return 2;
  491.     }
  492.  
  493.     printf(linehead);
  494.  
  495.     while (pfhline(inputfile,inp) == 0)
  496.     ;
  497.  
  498.     if (!feof(inp))
  499.     {
  500.     fprintf(stderr,nopfh,inputfile);
  501.     fclose(inp);
  502.     return 3;
  503.     }
  504.     else
  505.     {
  506.     if (hightime)
  507.     {
  508.         tm = localtime(&hightime);
  509.  
  510.         printf(hightext,hightime,
  511.            tm->tm_year,tm->tm_mon + 1,tm->tm_mday,
  512.            tm->tm_hour,tm->tm_min,tm->tm_sec,
  513.            ctime(&hightime));
  514.     }
  515.     }
  516.  
  517.     fclose(inp);
  518.     return 0;
  519. }
  520.  
  521. /* print table of contents for a series of downloaded files */
  522. pfhtoc (argc,argv)
  523.     int argc;
  524.     char *argv[];
  525.  
  526. {
  527.     int n,r = 0;
  528.     char *inputfile;
  529.     FILE *inp;
  530.  
  531.     printf(linehead);
  532.  
  533.     for (n = 1; n < argc; n++)
  534.     {
  535.     /* open next inputfile */
  536.  
  537.     if ((inp = fopen(inputfile = argv[n],"rb")) == NULL)
  538.     {
  539.         perror(inputfile);
  540.         r++;
  541.     }
  542.     else
  543.     {
  544.         /* display a single line of info from PFH */
  545.  
  546.         if (pfhline(inputfile,inp))
  547.         {
  548.         fprintf(stderr,nopfh,inputfile);
  549.         r++;
  550.         }
  551.  
  552.         fclose(inp);
  553.     }
  554.     }
  555.  
  556.     return r;
  557. }
  558.  
  559. /* display a single line of info from PFH, like a BBS "l" command */
  560. int pfhline (filename,inp)
  561.     char *filename;
  562.     FILE *inp;
  563.  
  564. {
  565.     int id,id2,len,i;
  566.     unsigned long val;
  567.     unsigned int hsum,csum;
  568.     unsigned long file_id,length;
  569.     unsigned char file_type;
  570.     time_t file_time;
  571.     struct tm *tm;
  572.  
  573.     /* check magic number AA55 */
  574.  
  575.     if (fgetc(inp) != 0xaa || fgetc(inp) != 0x55)
  576.     return -1;
  577.  
  578.     csum = 0xaa + 0x55;
  579.  
  580.     /* set defaults */
  581.  
  582.     file_id = length = 0;
  583.     file_type = 0;
  584.     file_time = 0;
  585.     source[0] = dest[0] = title[0] = '\0';
  586.  
  587.     /* read header items */
  588.  
  589.     while ((id = fgetc(inp)) != EOF &&
  590.        (id2 = fgetc(inp)) != EOF &&
  591.        (len = fgetc(inp)) != EOF)
  592.     {
  593.     csum += id + id2 + len;            /* update header checksum */
  594.  
  595.     id |= id2 << 8;
  596.  
  597.     if (id == 0 && len == 0)        /* end of header? */
  598.         break;
  599.  
  600.     if (fread(data,1,len,inp) != len)    /* read data */
  601.         break;
  602.  
  603.     data[len] = '\0';
  604.  
  605.     if (len <= 4)
  606.     {
  607.         val = 0;
  608.  
  609.         for (i = 0; i < len; i++)
  610.         val |= (unsigned long) data[i] << (8 * i);
  611.     }
  612.  
  613.     /* special treatment for some header items */
  614.     switch (id)
  615.     {
  616.     case 0x0a:                /* header checksum */
  617.         hsum = (unsigned)val;        /* get it's value */
  618.         break;                /* and don't update csum */
  619.  
  620.     default:
  621.         for (i = 0; i < len; i++)
  622.         csum += data[i];        /* update header checksum */
  623.         break;
  624.     }
  625.  
  626.     /* interpret the interesting header items */
  627.     switch (id)
  628.     {
  629.     case 0x01:                /* file_number */
  630.         file_id = val;
  631.         break;
  632.  
  633.     case 0x02:                /* file_name */
  634.         strcpy(title,(char *)data);
  635.         break;
  636.  
  637.     case 0x04:                /* file_size */
  638.         length = val;
  639.         break;
  640.  
  641.     case 0x05:                /* create_time */
  642.         file_time = val;
  643.         break;
  644.  
  645.     case 0x08:                /* file_type */
  646.         file_type = val;
  647.         break;
  648.  
  649.     case 0x10:                /* source */
  650.         strcpy(source,(char *)data);
  651.         break;
  652.  
  653.     case 0x11:                /* AX.25 uploader */
  654.         if (source[0] == '\0')
  655.         strcpy(source,(char *)data);
  656.  
  657.         break;
  658.  
  659.     case 0x12:                /* upload_time */
  660.         file_time = val;
  661.  
  662.         if ((long)val > hightime)        /* keep highwater mark */
  663.         hightime = (long)val;
  664.         break;
  665.  
  666.     case 0x14:                /* destination */
  667.         strcpy(dest,(char *)data);
  668.         break;
  669.  
  670.     case 0x22:                /* title */
  671.         strcpy(title,(char *)data);
  672.         break;
  673.  
  674.     case 0x26:                /* user filename */
  675.         if (title[0] == '\0')
  676.         strcpy(title,(char *)data);
  677.  
  678.         break;
  679.     }
  680.     }
  681.  
  682.     if (hsum != csum)
  683.     fprintf(stderr,headcsum,filename,csum);
  684.     else {
  685.     printf("%08lx %02x%7lu %-12.12s%-10.10s",
  686.            file_id,file_type,length,dest,source);
  687.  
  688.     if (file_time)
  689.     {
  690.         tm = localtime(&file_time);
  691.  
  692.         printf("%02u%02u/%02u%02u",
  693.            tm->tm_mon + 1,tm->tm_mday,tm->tm_hour,tm->tm_min);
  694.     }
  695.     else
  696.         printf("????/????");
  697.  
  698.     printf(" %s\n",title);
  699.     }
  700.  
  701.     return 0;
  702. }
  703.  
  704. /* clean a directory file.  removes any duplicate entries and sorts it    */
  705. /* in upload_time order                            */
  706. int cleandir (filename)
  707.     char *filename;
  708.  
  709. {
  710.     FILE *dir;
  711.     unsigned char *p;
  712.     int id,id2,len,i;
  713.     unsigned long val;
  714.     unsigned int hsum,csum;
  715.     unsigned long file_id;
  716.     time_t ul_time;
  717.     struct dir_entry
  718.     {
  719.     struct dir_entry *next,*prev;
  720.     unsigned long file_id;
  721.     time_t ul_time;
  722.     unsigned int length;
  723.     unsigned char entry[1];
  724.     } *entry_list,*new,*find;
  725.  
  726.     /* open the existing dir file */
  727.  
  728.     if ((dir = fopen(filename,"rb")) == NULL)
  729.     {
  730.     perror(filename);
  731.     return 2;
  732.     }
  733.  
  734.     /* put dummy item in the list */
  735.  
  736.     if ((entry_list = (struct dir_entry *) malloc(sizeof(struct dir_entry))) == NULL)
  737.     {
  738.     fprintf(stderr,nomem);
  739.     fclose(dir);
  740.     return 5;
  741.     }
  742.  
  743.     entry_list->next = entry_list->prev = NULL;
  744.     entry_list->file_id = 0xffffffffL;
  745.     entry_list->ul_time = 0x7fffffffL;
  746.     entry_list->length = 0;
  747.  
  748.     /* read all items from directory */
  749.  
  750.     for (;;)
  751.     {
  752.     p = data;
  753.     file_id = 0;
  754.     ul_time = 0;
  755.  
  756.     /* check magic number AA55 */
  757.  
  758.     if ((*p++ = fgetc(dir)) != 0xaa || (*p++ = fgetc(dir)) != 0x55)
  759.     {
  760.         if (feof(dir))
  761.         break;
  762.  
  763.         fprintf(stderr,nopfh,filename);
  764.         fclose(dir);
  765.         return 3;
  766.     }
  767.  
  768.     csum = 0xaa + 0x55;
  769.  
  770.     /* read header items */
  771.  
  772.     while ((id = fgetc(dir)) != EOF &&
  773.            (id2 = fgetc(dir)) != EOF &&
  774.            (len = fgetc(dir)) != EOF)
  775.     {
  776.         *p++ = id;
  777.         *p++ = id2;
  778.         *p++ = len;
  779.         csum += id + id2 + len;        /* update header checksum */
  780.  
  781.         id |= id2 << 8;
  782.  
  783.         if (id == 0 && len == 0)        /* end of header? */
  784.         break;
  785.  
  786.         if (fread(p,1,len,dir) != len)    /* read data */
  787.         break;
  788.  
  789.         if (len <= 4)
  790.         {
  791.         val = 0;
  792.  
  793.         for (i = 0; i < len; i++)
  794.             val |= (unsigned long) p[i] << (8 * i);
  795.         }
  796.  
  797.         /* special treatment for some header items */
  798.         switch (id)
  799.         {
  800.         case 0x0a:                /* header checksum */
  801.         hsum = (unsigned)val;        /* get it's value */
  802.         break;                /* and don't update csum */
  803.  
  804.         case 0x12:                /* upload_time */
  805.         ul_time = val;            /* get it */
  806.         goto addcsum;            /* add to csum */
  807.  
  808.         case 0x01:                /* file_number */
  809.         file_id = val;            /* get it & add to csum */
  810.  
  811.         default:
  812.         addcsum:
  813.         for (i = 0; i < len; i++)
  814.             csum += p[i];        /* update header checksum */
  815.         break;
  816.         }
  817.  
  818.         p += len;
  819.     }
  820.  
  821.     if (hsum != csum)
  822.     {
  823.         fprintf(stderr,headcsum,filename,csum);
  824.         return 3;
  825.     }
  826.  
  827.     if (file_id == 0)
  828.         continue;
  829.  
  830.     /* save this file header in a list item */
  831.  
  832.     if ((new = (struct dir_entry *) malloc(sizeof(struct dir_entry) + (unsigned)(p - data))) == NULL)
  833.     {
  834.         fprintf(stderr,nomem);
  835.         fclose(dir);
  836.         return 5;
  837.     }
  838.  
  839.     new->next = new->prev = NULL;
  840.     new->file_id = file_id;
  841.     new->ul_time = ul_time;
  842.     new->length = (unsigned)(p - data);
  843.     memcpy(new->entry,data,new->length);
  844.  
  845.     /* scan the list to find any duplicate entry for this file_id */
  846.  
  847.     for (find = entry_list; find != NULL; find = find->next)
  848.         if (find->file_id == file_id)
  849.         {
  850.         /* it's a duplicate, delete it to keep latest copy */
  851.  
  852.         if (find->prev != NULL)
  853.             find->prev->next = find->next;
  854.         else
  855.             entry_list = find->next;
  856.  
  857.         if (find->next != NULL)
  858.             find->next->prev = find->prev;
  859.  
  860.         free(find);
  861.         break;
  862.         }
  863.  
  864.     /* scan the list to find it's place (insertion sort) */
  865.  
  866.     for (find = entry_list; find != NULL; find = find->next)
  867.         if (find->ul_time > ul_time)
  868.         {
  869.         /* has to be inserted before this one */
  870.  
  871.         if ((new->prev = find->prev) != NULL)
  872.             find->prev->next = new;
  873.         else
  874.             entry_list = new;
  875.  
  876.         new->next = find;
  877.         find->prev = new;
  878.         break;
  879.         }
  880.     }
  881.  
  882.     fclose(dir);
  883.  
  884.     /* write the new dir file */
  885.  
  886.     if ((dir = fopen(filename,"wb")) == NULL)
  887.     {
  888.     perror(filename);
  889.     return 4;
  890.     }
  891.  
  892.     while (entry_list != NULL)
  893.     {
  894.     if (fwrite(entry_list->entry,1,entry_list->length,dir) != entry_list->length)
  895.     {
  896.         perror(filename);
  897.         fclose(dir);
  898.         unlink(filename);
  899.         return 6;
  900.     }
  901.  
  902.     entry_list = entry_list->next;
  903.     }
  904.  
  905.     fclose(dir);
  906.     return 0;
  907. }
  908.  
  909. /* add a PFH to a file, for upload to the server */
  910. int pfhadd (inputfile,outputfile)
  911.     char *inputfile;                /* inputfile name */
  912.     char *outputfile;                /* outputfile name */
  913.  
  914. {
  915.     FILE *inp,*out;
  916.     struct pfh *pi;
  917.     int len;
  918.     unsigned int csum;
  919.     unsigned long val;
  920.     unsigned long fsizepos,bcsumpos,hcsumpos,boffpos,bodypos;
  921.     unsigned char ftype = 0,ctype = 0;
  922.     time_t now;
  923.  
  924.     /* open inputfile */
  925.  
  926.     if ((inp = fopen(inputfile,"rb")) == NULL)
  927.     {
  928.     perror(inputfile);
  929.     return 2;
  930.     }
  931.  
  932.     /* create outputfile */
  933.  
  934.     if ((out = fopen(outputfile,"w+b")) == NULL)
  935.     {
  936.     perror(outputfile);
  937.     fclose(inp);
  938.     return 4;
  939.     }
  940.  
  941.     time(&now);                /* get default time */
  942.  
  943.     fputc(0xaa,out);            /* PFH magic number */
  944.     fputc(0x55,out);
  945.  
  946.     for (pi = pfh; pi->id != 0; pi++)
  947.     {
  948.     if (pi->flags & PROMPT ||    /* user-input item? */
  949.         (pi->id == 0x24 && ftype == 255) || /* file description? */
  950.         (pi->id == 0x25 && ctype == 255))    /* compression description? */
  951.     {
  952.         printf("%s: ",pi->title);    /* disp the prompt */
  953.  
  954.         if (gets((char *)data) == NULL)
  955.         data[0] = '\0';
  956.  
  957.         len = 0;            /* no conversion = no data */
  958.  
  959.         switch (pi->type)        /* conversion depending on type */
  960.         {
  961.         case TEXT:
  962.         len = (int)strlen((char *)data); /* use user-supplied data len */
  963.  
  964.         if (pi->len != 0 && len > pi->len)
  965.             len = pi->len;
  966.         break;
  967.  
  968.         case BYTE:
  969.         case WORD:
  970.         case LONG:
  971.         val = atol((char *)data);    /* get value of decimal input */
  972.         data[0] = (unsigned char)val;    /* convert to little-endian */
  973.         data[1] = (unsigned char)(val >> 8);
  974.         data[2] = (unsigned char)(val >> 16);
  975.         data[3] = (unsigned char)(val >> 24);
  976.         len = pi->type;
  977.         break;
  978.  
  979.         case COMP:
  980.         if (strstr((char *)data,"arc") != NULL)
  981.             data[0] = 1;
  982.         else
  983.             if (strstr((char *)data,"zip") != NULL)
  984.             data[0] = 2;
  985.             else
  986.             data[0] = (unsigned char)atoi((char *)data);
  987.  
  988.         len = 1;
  989.         }
  990.     }
  991.     else                /* else must be fixed item */
  992.     {
  993.         memset(data,(pi->flags & SPACE? ' ':'\0'),len = pi->len);
  994.     }
  995.  
  996.     switch (pi->id)            /* special treatment for some items */
  997.     {
  998.     case 0x04:            /* file_size */
  999.         fsizepos = ftell(out) + 3;
  1000.         break;
  1001.  
  1002.     case 0x05:            /* create_time */
  1003.         data[0] = (unsigned char)now; /* convert time to little-endian */
  1004.         data[1] = (unsigned char)(now >> 8);
  1005.         data[2] = (unsigned char)(now >> 16);
  1006.         data[3] = (unsigned char)(now >> 24);
  1007.         break;
  1008.  
  1009.     case 0x08:            /* file_type */
  1010.         ftype = data[0];
  1011.         break;
  1012.  
  1013.     case 0x09:            /* body_checksum */
  1014.         bcsumpos = ftell(out) + 3;
  1015.         break;
  1016.  
  1017.     case 0x0a:            /* header_checksum */
  1018.         hcsumpos = ftell(out) + 3;
  1019.         break;
  1020.  
  1021.     case 0x0b:            /* body_offset */
  1022.         boffpos = ftell(out) + 3;
  1023.         break;
  1024.  
  1025.     case 0x19:            /* compression_type */
  1026.         ctype = data[0];
  1027.         break;
  1028.  
  1029.     case 0x26:            /* user_filename */
  1030.         strcpy((char *)data,inputfile);
  1031.         len = (int)strlen((char *)data);
  1032.         break;
  1033.     }
  1034.  
  1035.     if (len != 0 || (pi->flags & MAND))
  1036.     {
  1037.         fputc((unsigned char)pi->id,out); /* write the item */
  1038.         fputc((unsigned char)(pi->id >> 8),out);
  1039.         fputc((unsigned char)len,out);
  1040.         fwrite(data,1,len,out);
  1041.     }
  1042.     }
  1043.  
  1044.     fputc(0,out);            /* terminate PFH */
  1045.     fputc(0,out);
  1046.     fputc(0,out);
  1047.  
  1048.     /* get body offset */
  1049.  
  1050.     bodypos = ftell(out);
  1051.  
  1052.     /* copy file to output, taking checksum */
  1053.  
  1054.     csum = 0;
  1055.  
  1056.     while ((len = (int)fread(data,1,sizeof(data),inp)) != 0) /* read data */
  1057.     {
  1058.     fwrite(data,1,len,out);        /* write to output */
  1059.  
  1060.     while (len > 0)            /* update checksum */
  1061.         csum += data[--len];
  1062.     }
  1063.  
  1064.     /* store total file size */
  1065.  
  1066.     val = ftell(out);
  1067.     fseek(out,fsizepos,0);
  1068.     fputc((unsigned char)val,out);
  1069.     fputc((unsigned char)(val >> 8),out);
  1070.     fputc((unsigned char)(val >> 16),out);
  1071.     fputc((unsigned char)(val >> 24),out);
  1072.  
  1073.     /* store calculated body checksum */
  1074.  
  1075.     fseek(out,bcsumpos,0);
  1076.     fputc((unsigned char)csum,out);
  1077.     fputc((unsigned char)(csum >> 8),out);
  1078.  
  1079.     /* set correct body offset */
  1080.  
  1081.     fseek(out,boffpos,0);
  1082.     fputc((unsigned char)bodypos,out);
  1083.     fputc((unsigned char)(bodypos >> 8),out);
  1084.  
  1085.     /* calculate header checksum */
  1086.  
  1087.     csum = 0;
  1088.     fseek(out,0L,0);
  1089.  
  1090.     while (bodypos-- > 0)
  1091.     csum += fgetc(out);
  1092.  
  1093.     /* store calculated header checksum */
  1094.  
  1095.     fseek(out,hcsumpos,0);
  1096.     fputc((unsigned char)csum,out);
  1097.     fputc((unsigned char)(csum >> 8),out);
  1098.  
  1099.     if (ferror(out))
  1100.     fprintf(stderr,writeerr,outputfile);
  1101.  
  1102.     fclose(inp);
  1103.     fclose(out);
  1104.     return 0;
  1105. }
  1106.  
  1107.